#include "sock.hpp"
#include "common.hpp"
#include "addr.hpp"
#include <unistd.h>
#include <algorithm>
class selectserver
{

    const static int size = sizeof(fd_set) * 8;
    const static int defaultfd = -1;

public:
    selectserver(int port) : _is_running(0), _listenfd(make_unique<Tcpsocket>())
    {
        _listenfd->arrangesock(port);
        // 对每次更新select 的rfd数组进行初始化：
        for (int i = 0; i < size; i++)
            _fd_arr[i] = defaultfd;
        _fd_arr[0] = _listenfd->Fd(); // 规定0号位置是套接字的fd
    }

    void start()
    {
        _is_running = 1;
        while (_is_running)
        {
            int max_fd = -1;
            fd_set rfds;    // 定义fds集合
            FD_ZERO(&rfds); // 清空fds
            for (int i = 0; i < size; i++)
            {
                if (_fd_arr[i] == defaultfd)
                    continue;
                FD_SET(_fd_arr[i], &rfds);
                max_fd = max(max_fd, _fd_arr[i]);
            }
            struct timeval to = {0, 0};                                   // 非阻塞等待
            int n = select(max_fd + 1, &rfds, nullptr, nullptr, nullptr); // 阻塞等待
            if (n > 0)
            {
                use_log(loglevel::DEBUG) << "读（写）事件就绪!";
                Dispatcher(rfds);
            }
            else if (n == 0)
            {

                use_log(loglevel::DEBUG) << "等待超时!";
                break;
            }
            else
            {
                   cout<<"错误 ："<<n<<endl;
                use_log(loglevel::DEBUG) << "select 错误";
                break;
            }
        }
    }

    void Dispatcher(fd_set &rfds)
    {
        for (int i = 0; i < size; i++)
        {
            if (_fd_arr[i] == defaultfd)
                continue;
            // 后面对数组中有效的fd进行检查是否就绪：分listenfd与普通fd：
            if (FD_ISSET(_fd_arr[i], &rfds))
            {

                if (_fd_arr[i] == _listenfd->Fd())
                    Acceper(); // 去等待队列接收新链接
                else
                    Recver(_fd_arr[i], i); // 读取对应缓冲区数据
            }
        }
    }

    void Acceper()
    {
        inetaddr client;
        int newfd = _listenfd->Accept(&client);
        int i = 0;
        for (i = 0; i < size; i++)
        {
            if (_fd_arr[i] == defaultfd)
            {
                _fd_arr[i] = newfd;
                break;
            } // 找到空的位置进行新的fd填入
        }
        // fd_set的对应位置都爆满了，也就是服务器接收的客户上线了：
        if (size == i)
        {

            use_log(loglevel::DEBUG) << "select full";
            close(newfd);
        }
    }

    void Recver(int fd, int pos)
    {  
         //tcp面向字节流，可能读不完整，这里暂不处理
        char buf[1024] = {0};
        int n = recv(fd, buf, sizeof(buf) - 1, 0);
        if (n > 0)
        {
            buf[n] = 0;
            cout << " client say @  : " << buf << endl;
        }
        else if (n == 0)
        {
            use_log(loglevel::DEBUG) << "client exit";
            close(fd);
            _fd_arr[pos] = defaultfd;
        }

        else
        {

            use_log(loglevel::DEBUG) << "Recv error";
            close(fd);
            _fd_arr[pos] = defaultfd;
        }
    }
    void stop()
    {
        _is_running = 0;
    }
    ~selectserver() {}

private:
    bool _is_running;
    unique_ptr<Socket> _listenfd;
    int _fd_arr[size];
};
